package com.project.common.web.biz.impl;

import com.project.common.web.biz.RSAService;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;
import org.yun.common.utils.RSAUtil;
import org.yun.common.utils.appInterface.CustomException;
import org.yun.common.utils.appInterface.RESPONSE_CODE_ENUM;
import org.yun.common.utils.redis.RedisClient;

import javax.annotation.Resource;
import java.security.KeyPair;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.HashMap;
import java.util.Map;

@Service("rsaServiceImpl")
public class RSAServiceImpl implements RSAService {

    private static final long serialVersionUID = 6323658208980628181L;

    @Resource(name = "redisClient")
    private RedisClient redisClient;

    /**
     * 生成js密钥并且返回公钥参数【后台登录使用】
     *
     * @param cacheKey redisKey
     * @return
     */
    public Map<String, String> generateJsKey(String cacheKey) {
        return generateJsKey(cacheKey, 18000);
    }

    /**
     * 生成js密钥并且返回公钥参数
     *
     * @param cacheKey redisKey
     * @param expire   过期时间，单位：秒
     * @return
     */
    public Map<String, String> generateJsKey(String cacheKey, int expire) {
        KeyPair kp = RSAUtil.generateKeyPair();

        RSAPublicKey publicKey = (RSAPublicKey) kp.getPublic();
        RSAPrivateKey privateKey = (RSAPrivateKey) kp.getPrivate();

        redisClient.setAndExpire(cacheKey, privateKey, expire);

        Map<String, String> pkMap = new HashMap<String, String>();

        pkMap.put("modulus", new String(Hex.encodeHex(publicKey.getModulus().toByteArray())));
        pkMap.put("exponent", new String(Hex.encodeHex(publicKey.getPublicExponent().toByteArray())));

        return pkMap;
    }

    /**
     * 生成加密公钥参数【APP接口使用】
     *
     * @param cacheKey redisKey
     * @return
     */
    public Map<String, String> generateKey(String cacheKey) {
        return generateKey(cacheKey, 18000);
    }

    /**
     * 生成加密公钥参数【APP接口中使用】
     *
     * @param cacheKey redisKey
     * @param expire   过期时间，单位：秒
     * @return
     */
    public Map<String, String> generateKey(String cacheKey, int expire) {

        // 生成秘钥对
        KeyPair kp = RSAUtil.generateKeyPair();
        RSAPublicKey publicKey = (RSAPublicKey) kp.getPublic();
        RSAPrivateKey privateKey = (RSAPrivateKey) kp.getPrivate();

        // 保存解密私钥参数
        redisClient.setAndExpire(cacheKey, privateKey, expire);

        // 封装返回公钥参数结合
        Map<String, String> pkMap = new HashMap<String, String>();
        pkMap.put("modulus", Base64.encodeBase64String(publicKey.getModulus().toByteArray()));
        pkMap.put("exponent", Base64.encodeBase64String(publicKey.getPublicExponent().toByteArray()));
        return pkMap;
    }


    /**
     * 根据私钥缓存KEY移除私钥【APP接口使用】
     *
     * @param cacheKey redisKey
     */
    public void removePrivateKey(String cacheKey) {
        redisClient.del(cacheKey);
    }

    /**
     * 根据缓存KEY RSA解密【后台登录使用】
     *
     * @param param    Redis 缓存KEY
     * @param cacheKey redisKey
     * @return
     */
    public String decryptJsParameter(String param, String cacheKey) {
        try {
            if (StringUtils.isNotBlank(param)) {
                RSAPrivateKey privateKey = (RSAPrivateKey) redisClient.get(cacheKey);
                if (StringUtils.isNotEmpty(param)) {
                    byte[] decrypt = RSAUtil.decrypt(privateKey, Hex.decodeHex(param.toCharArray()));
                    String s = new String(decrypt);
                    String s1 = String.valueOf(decrypt);
                    String s2 = decrypt.toString();
                    return StringUtils.reverse(s1);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 解密RSA公钥加密串【APP接口使用】
     *
     * @param param    RSA公钥加密后的字符串
     * @param cacheKey Redis中私钥KEY
     * @return
     */
    public String decryptParameter(String param, String cacheKey) {
        if (StringUtils.isNotBlank(param)) {
            RSAPrivateKey privateKey = (RSAPrivateKey) redisClient.get(cacheKey);
            if (StringUtils.isNotEmpty(param)) {
                return RSAUtil.decrypt(privateKey, param);
            }
        }
        return null;
    }

    /**
     * 解密RSA公钥加密串 - 有模式
     *
     * @param mode     解密模式
     * @param param    RSA公钥加密后的字符串
     * @param cacheKey Redis中私钥KEY
     * @return
     */
    public String decryptParameter(String mode, String param, String cacheKey) {
        if (StringUtils.isNotBlank(param)) {
            RSAPrivateKey privateKey = (RSAPrivateKey) redisClient.get(cacheKey);
            if (StringUtils.isNotEmpty(param)) {
                return RSAUtil.decrypt(mode, privateKey, param);
            }
        }
        return null;
    }

    /**
     * 对已进行RSA加密的密码进行解密
     *
     * @param accoPass   加密的密码
     * @param privateKey RedisConsts中非对称加密私钥设置+UID
     * @param mode       加密模式
     * @return 解密后的密码
     */
    public String rsaDecrypt(String accoPass, String privateKey, String mode) {
        try {
            //APP用的解密
            accoPass = decryptParameter(mode, accoPass, privateKey);
            if (StringUtils.isBlank(accoPass)) {
                throw new CustomException(RESPONSE_CODE_ENUM.RSA_DECRYPTION_ERROR);
            } else {
                return accoPass;
            }
        } catch (Exception e) {
            throw new CustomException(RESPONSE_CODE_ENUM.RSA_DECRYPTION_ERROR);
        }
    }

}
